<?php defined('SYSPATH') or die('No direct script access.');
/**
 * @file rest.php
 * @brief 修改Rest类
 * @author Lionel Tsai
 * @version 1.0
 * @date 2012-02-17
 */

abstract class Controller_REST extends Kohana_Controller_REST {
	/** 重定义映射*/
	protected  $_action_map = array(
			'GET'    => 'get',
			'POST'   => 'post',
			'PUT'    => 'put',
			'DELETE' => 'delete',
			);
	/** 验证开关*/
	protected $_ifauth = FALSE;
	protected $_request_params = array();

	public function before()
	{
		$this->_request_params = array(
			'method' => $this->request->method()
			, 'controller' => $this->request->controller()
			, 'action' => $this->request->action()
			, 'directory' => $this->request->directory()
		);

		$raw = file_get_contents("php://input");
		parent::before();
		if($this->request->action() !== 'invalid' && $this->_action_requested !== 'index' )
		{
			$action = $this->_action_requested . '_' . $this->request->action();
			$this->request->action($action);
		}

		/** 验证token*/
		elseif($this->_ifauth and !$this->authorized())
		{
			$this->request->action = 'index';
		}

		/** 一般用户权限*/	
		$_POST = json_decode($raw, true);
	}

	public function action_index()
	{
	}

	public function authorized()
	{
		//如果系统忽略，返回true
			
		//
		$auth = Auth::instance();
		if(!$auth->use_sid()) {
			/**
			 * @brief 无sid，若提供appkey，看app是否需要登录
			 *			若需登录，返回未登录
			 *			否则，检查登录权限
			 */
			do {
				if(!isset($_GET['appkey']))
					break;

				/** 若需要登录，判断登录权限*/
				$app = ORM::factory('app', array('app_key' => $_GET['appkey']));
				if((BOOL)$app->needlogin)
					break;
				
				/** 应用是否有权限*/
				if($app->authorized($this->_request_params))
					return true;
				else {
					$this->response->body('app_or_api_not_allowed')->status(406);
					return false;
				}
			}while(0);

			$this->response->body('no_login')->status(401);
			return false;
		}
	}
	
	/**
	 * @brief get current class name without 'Controller_' prefix 
	 *
	 * @return method_info array
	 */
	protected function method_info() {
		$methodName = strtolower(get_class($this));
		$methodName = preg_replace('/controller_/', '', $methodName);
		return array(
			'methodName' => $methodName,
		);
	}
	
	/**
	 * @brief get the object from given $id
	 *
	 * @param $id
	 *
	 * @return object json data, structure:
	 * {
	 *		flag:[0 or 1],
	 *		num:[list array count],
	 *		list:[{}{}...],
	 */
	protected function get_objc($id) {
		$method_info = $this->method_info();
		$methodName = $method_info['methodName'];
		$object = ORM::factory($methodName, $id);

		if (!$object->loaded()){
			$ret['flag'] = 0;
			$ret['num'] = 0;
			$ret['description'] = $methodName.' not found!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(400);
			return;
		}
		$json_ret = json_encode($object->as_array());
		$this->response->body($json_ret)->status(200);
	}

	/**
	 * @brief get  object list json data. The attr should be 'start(开始位置), pos(结束位置), order(正序或倒序)' 
	 *
	 * @return object json data, structure:
	 * {
	 *		flag:[0 or 1],
	 *		num:[list array count],
	 *		list:[{}{}...],
	 * }
	 */
	protected function get_objc_list() {
		/** 获取起止条数*/
		$start = filter_input(INPUT_GET, 'start', FILTER_VALIDATE_INT);
		$pos = filter_input(INPUT_GET, 'pos', FILTER_VALIDATE_INT);
		$order = filter_input(INPUT_GET, 'order');
		$order = ($order and ($order == 'asc' or $order == 'desc')) ? $order : 'asc';
		$start = ($start) ? $start : 0;
		$pos = ($pos) ? $pos : PHP_INT_MAX;

		$method_info = $this->method_info();
		$methodName = $method_info['methodName'];
		$objc = ORM::factory($methodName);
		
		$pid = $objc->primary_key();
		$objc->order_by($pid,$order);
		
		$objcs = $objc
				->offset($start)
				->limit($pos)
				->find_all();
		if(!$objcs->count())
		{
			$ret['flag'] = 0;
			$ret['num'] = 0;
			$ret['description'] = $methodName.' not found!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(400);
			return;
		}
		$ret['flag'] = 1;		
		$ret['num'] = $objcs->count();
		$ret['list'] = array();
		foreach($objcs as $obj)
		{
			$ret['list'][] = $obj->as_array();
		}
		$json_ret = json_encode($ret);
		$this->response->body($json_ret)->status(200);		

	}

	public function action_get($id = NULL) {
		if ($id === NULL){
			$this->get_objc_list();
		}
		else {
			$this->get_objc($id);
		}
	}
	
	public function action_post() {
		$method_info = $this->method_info();
		$methodName = $method_info['methodName'];

		$objc = ORM::factory($methodName);
		if(!$_POST)
		{
			$ret['flag'] = 0;
			$ret['description'] = $methodName.' not found!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(400);
			return;
		}
		try
		{
			$objc->values($_POST)->check()->save();
			$ret['flag'] = 1;
			$ret['description'] = $methodName.' add success!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(200);
		}
		catch(ORM_Validation_Exception $e)
		{
			$ret['flag'] = 0;
			
			$errors = $e->errors();

			foreach($errors as $k=>$v)
			{
				$ret['error_description_'.$k] = $k.':not available';
			}
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(206);

		}
		catch(Exception $err)
		{
			$ret['flag'] = 0;
			$ret['error_description'] = $err->getMessage();
			$json_ret = json_encode($ret);			
			$this->response->body($json_ret)->status(500);
		}
	}
	
	public function action_put($id) {
		$method_info = $this->method_info();
		$methodName = $method_info['methodName'];

		$objc = ORM::factory($methodName, $id);

		if(!$objc->loaded())
		{
			$ret['flag'] = 0;
			$ret['description'] = $methodName.' with that id not found!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(206);

			return;
		}
		try 
		{
			$objc->values($this->request->post())->check()->update();
			$ret['flag'] = 1;
			$ret['description'] = $methodName.' update success!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(200);
		}
		catch (ORM_Validation_Exception $e)
		{/** 验证错误处理*/
			$ret['flag'] = 0;
			
			$errors = $e->errors();

			foreach($errors as $k=>$v)
			{
				$ret['error_description_'.$k] = $k.':not available';
			}
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(206);
		}
		catch(Exception $err)
		{/** 其他错误处理*/
			$ret['flag'] = 0;
			$ret['error_description'] = $err->getMessage();
			$json_ret = json_encode($ret);			
			$this->response->body($json_ret)->status(500);
		}
		
	}
	public function action_delete($id) {
		$method_info = $this->method_info();
		$methodName = $method_info['methodName'];

		$objc = ORM::factory($methodName, $id);


		if(!$objc->loaded())
		{
			$ret['flag'] = 0;
			$ret['description'] = $methodName.' with that id not found!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(206);
			return;
		}
		try
		{
			$objc->delete();
			$ret['flag'] = 1;
			$ret['description'] = $methodName.' delete success!';
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(200);
		}
		catch(Exception $err)
		{
			$ret['flag'] = 0;
			$ret['error_description'] = $err->getMessage();
			$json_ret = json_encode($ret);
			$this->response->body($json_ret)->status(500);
		}	
	}
}
